package org.jeecg.modules.demo.mes.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.modules.demo.mes.constant.StationMessage;
import org.jeecg.modules.demo.mes.controller.query.ProductionProcessQuery;
import org.jeecg.modules.demo.mes.entity.*;
import org.jeecg.modules.demo.mes.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 生产过程业务类
 */
@Service
public class MesProductionProcessServiceImpl implements IMesProductionProcessService {
    @Autowired
    private StationMessage stationMessage;
    @Autowired
    private IMesBaseFactoryService mesBaseFactoryService;
    @Autowired
    private IMesWorkOrderService mesWorkOrderService;
    @Autowired
    private IMesWorkOrderDetailService mesWorkOrderDetailService;
    @Autowired
    private IMesTechnologyService mesTechnologyService;
    @Autowired
    private IMesTechnologyProcedureService mesTechnologyProcedureService;
    @Autowired
    private IMesMaterialDetailsService mesMaterialDetailsService;
    @Autowired
    private IMesOrderProcedureCheckService mesOrderProcedureCheckService;
    @Autowired
    private IMesOrderProcedureMaterialService mesOrderProcedureMaterialService;

    /**
     * @param field 字段
     * @return 工厂信息
     */
    @Override
    public MesBaseFactory queryFactoryMsgByField(String field) {
        if (StringUtils.equals(field, "factory")) {
            final List<MesBaseFactory> factoryList = mesBaseFactoryService.queryFactoriesByName(stationMessage.getFactoryName().trim());
            if (factoryList == null || factoryList.size() == 0) {
                throw new JeecgBootException("根据配置中的工厂名字查不到该工厂信息，请修改后重启后台项目再重新访问");
            }
            return factoryList.get(0);
        }
        if (StringUtils.equals(field, "workshop")) {
            final List<MesBaseFactory> workshopList = mesBaseFactoryService.queryFactoriesByName(stationMessage.getWorkshopName().trim());
            if (workshopList == null || workshopList.size() == 0) {
                throw new JeecgBootException("根据配置中的车间名字查不到信息，请修改后重启后台项目再重新访问");
            }
            return workshopList.get(0);
        }
        if (StringUtils.equals("line", field)) {
            final List<MesBaseFactory> lineList = mesBaseFactoryService.queryFactoriesByName(stationMessage.getLineName().trim());
            if (lineList == null || lineList.size() == 0) {
                throw new JeecgBootException("根据配置中的产线名字查不到信息，请修改后重启后台项目再重新访问");
            }
            return lineList.get(0);
        }
        final List<MesBaseFactory> stationList = mesBaseFactoryService.queryFactoriesByName(stationMessage.getStationName().trim());
        if (stationList == null || stationList.size() == 0) {
            throw new JeecgBootException("根据配置中的工位名字查不到信息，请修改后重启后台项目再重新访问");
        }
        return stationList.get(0);
    }

    @Override
    public Object queryWorkOrderByWorkOrderBarCode(String workOrderBarCode) {
        //1.首先查询工单
        final Map<String, Object> cxMap = new HashMap<>();
        cxMap.put("workOrderBarCode", workOrderBarCode);
        final List<MesWorkOrderDetail> workOrderDetailList = mesWorkOrderDetailService.queryMesWorkOrderDetailListSelective(cxMap);
        if (workOrderDetailList == null || workOrderDetailList.size() == 0) {
            throw new JeecgBootException("根据工单号查不到工单信息");
        }
        final MesWorkOrderDetail workOrderDetail = workOrderDetailList.get(0);
        //7.校验本道工序是否已经完成
        if (StringUtils.equals("2", workOrderDetail.getFinishStatus())) {
            final JSONObject stationProcedureJson = new JSONObject();
            stationProcedureJson.put("workOrderId", workOrderDetail.getWorkOrderId());
            stationProcedureJson.put("workOrderFinishStatus", workOrderDetail.getFinishStatus());
            return stationProcedureJson;
        }

        final MesWorkOrder mesWorkOrder = mesWorkOrderService.getById(workOrderDetail.getWorkOrderId());
        if (mesWorkOrder == null) {
            throw new JeecgBootException("获取工单信息为空");
        }
        //检查工单是否下发
        final String workOrderStatus = mesWorkOrder.getWorkOrderStatus();
        if (!StringUtils.equals("2", workOrderStatus)) {
            throw new JeecgBootException("该工单还未下发，请先操作下发");
        }
        //2.校验工单对应工厂、车间、产线信息是否对应
        final String factoryId = mesWorkOrder.getFactoryId();
        if (!StringUtils.equals(factoryId, queryFactoryMsgByField("factory").getId())) {
            throw new JeecgBootException("该工单不属于本工厂");
        }
        final String workshopId = mesWorkOrder.getWorkshopId();
        if (!StringUtils.equals(workshopId, queryFactoryMsgByField("workshop").getId())) {
            throw new JeecgBootException("该工单不属于本车间");
        }
        final String lineId = mesWorkOrder.getLineId();
        if (!StringUtils.equals(lineId, queryFactoryMsgByField("line").getId())) {
            throw new JeecgBootException("该工单不属于本产线");
        }
        //3.验证工艺
        cxMap.clear();
        cxMap.put("factoryId", factoryId);
        cxMap.put("workshopId", workshopId);
        cxMap.put("lineId", lineId);
        cxMap.put("technologyStatus", "1");
        final List<MesTechnology> mesTechnologyList = mesTechnologyService.queryTechnologyListSelective(cxMap);
        if (mesTechnologyList == null || mesTechnologyList.size() == 0) {
            throw new JeecgBootException("该产线还未创建工艺，请先配置工艺");
        }
        //4.验证工序
        final MesTechnology technology = mesTechnologyList.get(0);
        cxMap.clear();
        cxMap.put("technologyId", technology.getId());
        final List<MesTechnologyProcedure> mesTechnologyProcedureList = mesTechnologyProcedureService.queryTechnologyProcedureListSelective(cxMap);
        if (mesTechnologyProcedureList == null || mesTechnologyProcedureList.size() == 0) {
            throw new JeecgBootException("该产线还未创建工序，请先配置工序");
        }
        //5.验证工位
        MesTechnologyProcedure stationProcedure = null;
        MesTechnologyProcedure beforeProcedure = null;
        for (MesTechnologyProcedure procedure : mesTechnologyProcedureList) {
            if (stationProcedure != null) {
                //找到上一道工序
                beforeProcedure = procedure;
            }
            final String stationId = procedure.getStationId();
            if (StringUtils.equals(stationId, queryFactoryMsgByField("station").getId())) {
                stationProcedure = procedure;
            }
        }
        if (stationProcedure == null) {
            throw new JeecgBootException("该产线没有对应的工位，请检查后在查询");
        }
        //设置返回结果json
        final JSONObject stationProcedureJson = JSONObject.parseObject(JSON.toJSONString(stationProcedure));
        //通过工位和工序查询映射表是否已有
        final String stationAttribute = stationProcedure.getStationAttribute();
        cxMap.clear();
        cxMap.put("stationId", queryFactoryMsgByField("station").getId());
        cxMap.put("procedureId", stationProcedure.getId());
        if (StringUtils.equals(stationAttribute, "1")) {
            final List<MesOrderProcedureMaterial> mappings = mesOrderProcedureMaterialService.queryMappingListSelective(cxMap);
            if (mappings != null && mappings.size() > 0) {
                throw new JeecgBootException("本工位已经完成本工序的任务，请勿重复操作");
            }
        } else if (StringUtils.equals(stationAttribute, "2")) {
            final List<MesOrderProcedureCheck> mappings = mesOrderProcedureCheckService.queryMappingListSelective(cxMap);
            if (mappings != null && mappings.size() > 0) {
                throw new JeecgBootException("本工位已经完成本工序的任务，请勿重复操作");
            }
        } else if (StringUtils.equals("3", stationAttribute)) {
            final List<MesOrderProcedureMaterial> materialMappings = mesOrderProcedureMaterialService.queryMappingListSelective(cxMap);
            final List<MesOrderProcedureCheck> checkMappings = mesOrderProcedureCheckService.queryMappingListSelective(cxMap);
            if (materialMappings != null && materialMappings.size() > 0 && checkMappings != null && checkMappings.size() > 0) {
                throw new JeecgBootException("本工位已经完成本工序的任务，请勿重复操作");
            }
            if (materialMappings != null && materialMappings.size() > 0) {
                stationProcedureJson.put("currentMaterialBtnFinished", true);
            }
        }

        //6.校验上一道工序有没有完成
        if (beforeProcedure != null) {
            final String procedureId = beforeProcedure.getId();
            cxMap.clear();
            cxMap.put("procedureId", procedureId);
            cxMap.put("finishStatus", "2");
            final List<MesWorkOrderDetail> detailList = mesWorkOrderDetailService.queryMesWorkOrderDetailListSelective(cxMap);
            if (detailList == null || detailList.size() == 0) {
                throw new JeecgBootException("上道工序还未走完，请勿提前操作");
            }
        }

        //校验通过，将开始时间更新到工单中
        final Date now = new Date();
        workOrderDetail.setStartTime(now);
        workOrderDetail.setUpdateTime(now);
        workOrderDetail.setUpdateBy(JwtUtil.getUserName());
        mesWorkOrderDetailService.updateById(workOrderDetail);

        //添加返回相应的判断条件
        stationProcedureJson.put("workOrderId", workOrderDetail.getWorkOrderId());
        stationProcedureJson.put("workOrderFinishStatus", workOrderDetail.getFinishStatus());
        return stationProcedureJson;
    }

    /**
     * 获取物料条码详情
     *
     * @param materialBarCode 物料条码
     * @return
     */
    @Override
    public Object queryMaterialDetailByBarCode(String materialBarCode) {
        final Map<String, Object> cxMap = new HashMap<>();
        cxMap.put("materialBarCode", materialBarCode);
        final List<MesMaterialDetail> materialDetailsList = mesMaterialDetailsService.queryMaterialDetailsSelective(cxMap);
        if (materialDetailsList == null || materialDetailsList.size() == 0) {
            throw new JeecgBootException("物料条码不正确，请检查后重试");
        }
        if (materialDetailsList.size() > 1) {
            throw new JeecgBootException("通过物料条码查出多条数据，请检查数据库");
        }
        final MesMaterialDetail mesMaterialDetail = materialDetailsList.get(0);
        final String materialStatus = mesMaterialDetail.getMaterialStatus();
        if (StringUtils.equals("2", materialStatus)) {
            throw new JeecgBootException("该物料条码已被使用！");
        }
        return mesMaterialDetail;
    }

    /**
     * 完成物料操作
     *
     * @param procedureId      工序id
     * @param workOrderBarCode 工单条码
     * @param list             物料集合
     */
    @Override
    @Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
    public void finishMaterial(String procedureId, String workOrderBarCode, List<Map<String, Object>> list) {
        final Date now = new Date();
        final String userName = JwtUtil.getUserName();
        //1.将此工单填入完成时间，并设置为完成状态
        final MesTechnologyProcedure technologyProcedure = mesTechnologyProcedureService.getById(procedureId);
        final String stationAttribute = technologyProcedure.getStationAttribute();
        MesWorkOrderDetail workOrderDetail = null;
        if (StringUtils.equals("1", stationAttribute)) {
            //工位属性是“作业”，完成后本工单详情状态需要修改
            workOrderDetail = updateWorkOrderDetail(workOrderBarCode, now, userName);
            //3.检查该工序是否已经走完(如果这是工序的最后一步，就要更新该订单办结状态)
            updateWorkOrder(procedureId,workOrderDetail.getWorkOrderId());
        } else {
            //工位属性是“作业+检测”，所以作业完成后先不修改工单详情的状态
            workOrderDetail = mesWorkOrderDetailService.queryMesWorkOrderDetailByWorkOrderBarCode(workOrderBarCode);
        }
        //2.写入映射表
        if (list == null) {
            return;
        }
        final String stationId = queryFactoryMsgByField("station").getId();
        final String workOrderDetailId = workOrderDetail.getId();
        for (Map<String, Object> map : list) {
            final MesOrderProcedureMaterial mapping = new MesOrderProcedureMaterial();
            mapping.setWorkOrderDetailId(workOrderDetailId);
            mapping.setWorkOrderBarCode(workOrderBarCode);
            mapping.setStationId(stationId);
            mapping.setProcedureId(procedureId);
            mapping.setMaterialId((String) map.get("materialId"));
            mapping.setMaterialSequence((String) map.get("materialId_dictText"));
//            mapping.setMaterialBarCodes(JSONArray.toJSONString(map.get("materialBarCodeList")));
            mapping.setCreateBy(userName);
            mapping.setCreateTime(now);
            mapping.setUpdateBy(userName);
            mapping.setUpdateTime(now);
            mesOrderProcedureMaterialService.save(mapping);
        }

        // 3.将所有物料详情状态改为使用
        final List<String> materialBarCodeList = new ArrayList<>();
        for (Map<String, Object> map : list) {
            materialBarCodeList.addAll((Collection<? extends String>) map.get("materialBarCodeList"));
        }
        mesMaterialDetailsService.changeMaterialStatus("2", procedureId, materialBarCodeList, workOrderDetailId);
    }

    /**
     * 将此工单填入完成时间，并设置为完成状态
     */
    private MesWorkOrderDetail updateWorkOrderDetail(String workOrderBarCode, Date now, String userName) {
        final Map<String, Object> cxMap = new HashMap<>();
        cxMap.put("workOrderBarCode", workOrderBarCode);
        final List<MesWorkOrderDetail> workOrderDetailList = mesWorkOrderDetailService.queryMesWorkOrderDetailListSelective(cxMap);
        if (workOrderDetailList == null || workOrderDetailList.size() == 0) {
            throw new JeecgBootException("未查询到此工单，请检查");
        }
        if (workOrderDetailList.size() > 1) {
            throw new JeecgBootException("一个工单条码对应两条信息，请检查数据库");
        }

        final MesWorkOrderDetail workOrderDetail = workOrderDetailList.get(0);
        workOrderDetail.setEndTime(now);
        workOrderDetail.setFinishStatus("2");
        workOrderDetail.setUpdateBy(userName);
        workOrderDetail.setUpdateTime(now);
        mesWorkOrderDetailService.updateById(workOrderDetail);
        return workOrderDetail;
    }

    @Override
    @Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
    public void finishCheck(String procedureId, String workOrderBarCode, List<Map<String, Object>> list) {
        final Date now = new Date();
        final String userName = JwtUtil.getUserName();
        //1.将此工单填入完成时间，并设置为完成状态
        final MesWorkOrderDetail workOrderDetail = updateWorkOrderDetail(workOrderBarCode, now, userName);
        //2.写入映射表
        if (list == null) {
            return;
        }
        final String stationId = queryFactoryMsgByField("station").getId();
        for (Map<String, Object> map : list) {
            final MesOrderProcedureCheck checkMapping = new MesOrderProcedureCheck();
            checkMapping.setCheckItem((String) map.get("checkItem"));
            checkMapping.setCheckQuantity(String.valueOf(map.get("quantity")));
            checkMapping.setCreateBy(userName);
            checkMapping.setCreateTime(now);
            if (map.get("judge") != null) {
                checkMapping.setJudgeResult(String.valueOf(map.get("judge")));
            }
            checkMapping.setProcedureId(procedureId);
            checkMapping.setStationId(stationId);
            checkMapping.setUpdateBy(userName);
            checkMapping.setUpdateTime(now);
            checkMapping.setWorkOrderBarCode(workOrderBarCode);
            checkMapping.setWorkOrderDetailId(workOrderDetail.getId());
            mesOrderProcedureCheckService.save(checkMapping);
        }
        //3.检查该工序是否已经走完(如果这是工序的最后一步，就要更新该订单办结状态)
        updateWorkOrder(procedureId,workOrderDetail.getWorkOrderId());
    }

    /**
     * 如果该工序已经走到最后一个，就要更新工单的办结状态
     */
    private void updateWorkOrder(String procedureId, String workOrderId) {
        final MesTechnologyProcedure procedure = mesTechnologyProcedureService.getById(procedureId);
        final MesTechnologyProcedure procedureMax = mesTechnologyProcedureService.queryTechnologyProcedureMaxByTechnologyId(procedure.getTechnologyId());
        if (!StringUtils.equals(procedureId,procedureMax.getId())){
            return;
        }
        //当前工序是最后一道工序，办理完成后更新工单表
        final MesWorkOrder mesWorkOrder = mesWorkOrderService.getById(workOrderId);
        if (mesWorkOrder==null){
            throw new JeecgBootException("根据工单id（"+workOrderId+"）获取不到工单信息");
        }
        mesWorkOrder.setFinishStatus("2");
        mesWorkOrder.setUpdateBy(JwtUtil.getUserName());
        mesWorkOrder.setUpdateTime(new Date());
        mesWorkOrderService.updateById(mesWorkOrder);
    }

    @Override
    public List<MesWorkOrderDetail> queryProcedureWorkOrderList(ProductionProcessQuery query) {
        if (query == null) {
            return new ArrayList<>();
        }
        final Map<String, Object> cxMap = new HashMap<>();
        cxMap.clear();
        cxMap.put("workOrderId", query.getWorkOrderId());
        cxMap.put("finishStatus", query.getFinishStatus());
        cxMap.put("pageNo", query.getPageNo());
        cxMap.put("pageSize", query.getPageSize());
        return mesWorkOrderDetailService.queryMesWorkOrderDetailListSelective(cxMap);
    }

    @Override
    public Integer queryProcedureWorkOrderCount(ProductionProcessQuery query) {
        if (query == null) {
            return 0;
        }
        final Map<String, Object> cxMap = new HashMap<>();
        cxMap.clear();
        cxMap.put("workOrderId", query.getWorkOrderId());
        cxMap.put("finishStatus", query.getFinishStatus());
        cxMap.put("pageNo", query.getPageNo());
        cxMap.put("pageSize", query.getPageSize());
        return mesWorkOrderDetailService.queryProcedureWorkOrderCount(cxMap);
    }


}
